home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 16
/
CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso
/
CUCD
/
Graphics
/
Ghostscript
/
source
/
gsdsc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-12-29
|
8KB
|
316 lines
/* Copyright (C) 1994 Aladdin Enterprises. All rights reserved. */
/* dsc.c */
/* Parse DSC comments from a PostScript file. */
#include "stdpre.h"
#include <stdio.h>
#include <malloc.h>
#include <math.h>
#ifndef SEEK_SET
# define SEEK_SET 0
#endif
/* Define the maximum length of a line in a DSC-conforming file. */
/* This is 255 characters + 2 for newline + 1 for null. */
#define line_size 258
/* Test whether a line begins with %%. */
#define is_dsc_comment(line) ((line)[0] == '%' && (line)[1] == '%')
/* Test whether a string begins with a given prefix. */
#define has_prefix(str, pre) !strncmp(str, pre, strlen(pre))
/* Faster test if prefix is a literal string. */
#define has_lit_prefix(str, litpre) !strncmp(str, litpre, sizeof(litpre) - 1)
/* Test whether a line is a specific DSC comment. */
#define has_dsc_prefix(line, litpre)\
(is_dsc_comment(line) && has_lit_prefix(line, litpre))
/* Define a bounding box structure. */
#define LLX 0
#define LLY 1
#define URX 2
#define URY 3
/* ------ Internal routines ------ */
/* Allocate a block with malloc, exiting on failure. */
private void *
dsc_malloc(size_t size)
{ void *blk = malloc(size);
if ( blk == 0 )
{ fprintf(stderr, "Unable to allocate object; giving up.\n");
exit(255);
}
return blk;
}
/* Copy a given amount of data from one file to another (to != NULL) or */
/* skip a given amount of data in a file without using fseek (to == NULL). */
#define fcpy_size 5000
private void
fcpy(FILE *to, FILE *from, long len)
{ char buf[fcpy_size];
size_t count;
for ( ; len > 0; len -= count )
{ count = (len > fcpy_size ? fcpy_size : len);
fread(buf, sizeof(char), count, from);
if ( to != NULL )
fwrite(buf, sizeof(char), count, to);
}
}
#undef fcpy_size
/*
* Copy (or skip) a %%BeginBinary/%%EndBinary section.
* Return the number of bytes copied or skipped.
*/
private long
copy_binary(FILE *to, FILE *from, const char *line)
{ long count;
if ( sscanf(line + 14, "%ld", &count) == 1 )
fcpy(to, from, count);
else
count = 0;
return count;
}
/*
* Copy (or skip) a %%BeginData/%%EndData section.
* Return the number of bytes copied or skipped.
*/
private long
copy_data(FILE *to, FILE *from, const char *line)
{ long count, amount = 0;
char str[line_size];
str[0] = '\0';
if ( sscanf(line + 12, "%ld %*s %s", &count, str) >= 1 )
{ if ( !strcmp(str, "Lines") )
for ( ; count > 0; --count )
{ if ( !fgets(str, line_size, from) )
break;
amount += strlen(str);
if ( to != NULL )
fputs(str, to);
}
else
{ amount = count;
fcpy(to, from, count);
}
}
return amount;
}
/*
* Read the next line from the input. Skip over embedded data, and also
* skip sections (such as procsets, fonts, and included documents) that
* are not part of the main document flow.
* Return a pointer to the input line, or NULL if we reached EOF.
*/
private void skip_region(P4(char *, FILE *, long *, const char *));
private char *
next_line(char *line, FILE *in, long *pstart, long *plen)
{ if ( pstart )
*pstart = ftell(in);
*plen = 0;
for ( ; ; )
{ if ( !fgets(line, line_size, in) ) /* EOF */
{ line[0] = 0;
return 0;
}
*plen += strlen(line);
if ( !has_dsc_comment(line, "Begin") )
break;
else if ( has_lit_prefix(line+7, "Binary:") )
{ *plen += copy_binary(NULL, in, line);
skip_region(line, in, plen, "EndBinary");
}
else if ( has_lit_prefix(line+7, "Data:") )
{ *plen += copy_data(NULL, in, line);
skip_region(line, in, plen, "EndData");
}
else if ( has_lit_prefix(line+7, "Feature:") )
skip_region(line, in, plen, "EndFeature");
else if ( has_lit_prefix(line+7, "File:") )
skip_region(line, in, plen, "EndFile");
else if ( has_lit_prefix(line+7, "Font:") )
skip_region(line, in, plen, "EndFont");
else if ( has_lit_prefix(line+7, "ProcSet:") )
skip_region(line, in, plen, "EndProcSet");
else if ( has_lit_prefix(line+7, "Resource:") )
skip_region(line, in, plen, "EndResource");
}
return line;
}
/*
* Skip a region of the PostScript file up to a given %%End comment.
*/
private void
skip_region(char *line, FILE *in, long *plen, const char *end_comment)
{ do
{ long len;
if ( next_line(line, in, NULL, &len) == NULL )
break;
*plen += len;
}
while ( !has_dsc_prefix(line, end_comment) );
}
/*
* Scan a bounding box argument. Return 1 iff we found one.
*/
private int
scan_bbox(const char *line, int bbox[4])
{ float fx0, fy0, fx1, fy1;
if ( sscanf(line, "%d %d %d %d", &bbox[LLX], &bbox[LLY],
&bbox[URX], &bbox[URY]) == 4
)
return 1;
if ( sscanf(line, "%f %f %f %f", &fx0, &fy0, &fx1, &fy1) != 4 )
return 0;
bbox[LLX] = (int)floor(fx0);
bbox[LLY] = (int)floor(fy0);
bbox[URX] = (int)ceil(fx1);
bbox[URY] = (int)ceil(fy1);
return 1;
}
/*
* Scan a text argument, recognizing escapes if it is a parenthesized string.
* If the string is not parenthesized then if rest = 1, take the rest of
* the line as the argument; if rest = 0, only take up to the next whitespace.
*/
#define scan_text_arg(line, endp) scan_text(line, endp, 0)
#define scan_line_arg(line, endp) scan_text(line, endp, 1)
private const char *
scan_text(const char *line, const char **endp, int rest)
{ char buf[line_size];
const char *lp = line;
char *bp = buf;
char *arg;
while ( *lp == ' ' || *lp == '\t' )
lp++;
if ( *lp == '(' )
{ int level = 1;
lp++;
for ( ; ; )
switch ( *bp++ = *lp++ )
{
case '\\':
switch ( *lp++ )
{
case 'n':
bp[-1] = '\n'; break;
case 'r':
bp[-1] = '\r'; break;
case 't':
bp[-1] = '\t'; break;
case 'b':
bp[-1] = '\b'; break;
case 'f':
bp[-1] = '\f'; break;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
{ int c = lp[-1] - '0';
int d = *lp;
if ( d >= '0' && d <= '7' )
{ c = (c << 3) + d - '0';
d = *++lp;
if ( d >= '0' && d <= '7' )
{ c = (c << 3) + d - '0';
lp++;
}
}
bp[-1] = c;
break;
}
case 0: /* unexpected EOF */
lp--;
goto out;
default:
bp[-1] = lp[-1];
}
break;
case '(':
++level;
break;
case ')':
if ( --level )
break;
case 0:
goto out;
default:
;
}
out: --bp;
}
else
{ /* Not quoted. */
while ( !(*lp == 0 || *lp == '\n' ||
(!rest && (*lp == ' ' || *lp == '\t')))
)
*bp++ = *lp++;
if ( bp == buf ) /* empty */
return NULL;
}
*bp = 0;
if ( endp )
*endp = lp;
arg = dsc_malloc(bp - buf + 1);
strcpy(arg, buf);
return arg;
}
/* ------ Public routines ------ */
/*
* Copy a section of a DSC-conforming PostScript file.
* Detect %%(Begin|End)(Binary|Data) comments and copy the intervening
* data as binary if necessary. If a sentinel is specified,
* stop copying when we reach a line that begins with the sentinel.
* If start < 0, don't seek before copying.
*/
private int dsc_copy_section(P6(FILE *from, FILE *to, long start, long end,
char *line, const char *sentinel));
void
dsc_copy(FILE *from, FILE *to, long start, long end)
{ char line[line_size];
dsc_copy_section(from, to, start, end, line, NULL);
}
char *
dsc_copy_until(FILE *from, FILE *to, long start, long end,
const char *sentinel)
{ char line[line_size];
int found = dsc_copy_section(from, to, start, end, line, sentinel);
if ( found )
{ char *ret = dsc_malloc(strlen(line) + 1);
strcpy(ret, line);
return ret;
}
return NULL;
}
private int
dsc_copy_section(FILE *from, FILE *to, long start, long end,
char *line, const char *sentinel)
{ int sent_len = (sentinel == 0 ? 0 : strlen(sentinel));
if ( start >= 0 )
fseek(from, start, SEEK_SET);
while ( ftell(from) < end )
{ long count;
fgets(line, line_size, from);
if ( sent_len )
{ if ( !strncmp(line, sentinel, sent_len) )
return 1;
}
fputs(line, to);
if ( !has_dsc_prefix(line, "Begin") )
;
else if ( has_lit_prefix(line + 7, "Binary:") )
copy_binary(to, from, line);
else if ( has_lit_prefix(line + 7, "Data:") )
copy_data(to, from, line);
}
return 0;
}